package control.service.impl;

import base.auth.JwtUtil;
import base.interactive.redis.RedisClusterUtils;
import base.standard.constant.ErrorCode;
import base.standard.constant.TokenKey;
import base.standard.exception.SimpleException;
import base.util.AssertUtils;
import base.util.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import control.mapper.authmanage.UserMapper;
import control.module.po.authmanage.RoleAuth;
import control.module.po.authmanage.UserRole;
import control.module.vo.authmanage.AuthVO;
import control.module.vo.usermanage.RoleAuthsVo;
import control.module.vo.usermanage.UserAuthVo;
import control.service.*;
import control.module.po.usermanage.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * User service
 *
 * @description:
 * @author: cyj
 * @date 2020 -10-26 08:51:17
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    /**
     * User role service
     */
    @Autowired
    private IUserRoleService userRoleService;

    /**
     * Role auth service
     */
    @Autowired
    private IRoleAuthService roleAuthService;

    /**
     * Role service
     */
    @Autowired
    private IRoleService roleService;

    /**
     * Auth service
     */
    @Autowired
    private IAuthService authService;

    @Autowired
    private RedisClusterUtils redisClusterUtils;

    @Override
    public User getByLoginId(String loginId) {
        User condition = new User().setLoginId(loginId);
        return this.baseMapper.selectOne(new QueryWrapper<User>(condition));
    }

    @Override
    public UserAuthVo getAuth(Integer id) {
        User user = Optional.ofNullable(getById(id)).orElseThrow(()-> new SimpleException(ErrorCode.USER_NOT_FOUND));
        UserAuthVo userAuthVo = BeanUtil.newInstanceAndCopy(user, UserAuthVo.class);
        userAuthVo.setRoles(assembleRoleAuths(id));
        return userAuthVo;
    }

    @Override
    public UserAuthVo getAuth(String loginId) {
        User user = Optional.ofNullable(getByLoginId(loginId)).orElseThrow(()-> new SimpleException(ErrorCode.USER_NOT_FOUND));
        UserAuthVo userAuthVo = BeanUtil.newInstanceAndCopy(user, UserAuthVo.class);
        userAuthVo.setRoles(assembleRoleAuths(user.getId()));
        return userAuthVo;
    }

    @Override
    public List<RoleAuthsVo> assembleRoleAuths(Integer id) {
        List<UserRole> userRoles = userRoleService.getByUserId(id);
        List<RoleAuthsVo> roleAuthsVos = BeanUtil.newInstanceAndCopyBatch(
                userRoles.stream().map(userRole -> roleService.getById(userRole.getRoleId()))
                        .collect(Collectors.toList()),
                RoleAuthsVo.class);
        // 批量初始化auths
        roleAuthsVos.stream().forEach(roleAuthsVo -> {
            roleAuthsVo.setAuth(new ArrayList<>());
            Integer roleId = roleAuthsVo.getId();
            List<RoleAuth> roleAuths = roleAuthService.getByRoleId(roleId);
            roleAuths.stream().forEach(roleAuth ->
                    Optional.ofNullable(
                            BeanUtil.newInstanceAndCopy(authService.getById(roleAuth.getAuthId()), AuthVO.class))
                            .ifPresent(roleAuthsVo.getAuth()::add));
        });
        return roleAuthsVos;
    }

    @Override
    public String login(String loginId, String password) {
        String ssoKey = TokenKey.USER_SSO_HASH.key + loginId;
        AssertUtils.check(null != redisClusterUtils.get(ssoKey), ErrorCode.USER_HAS_LOGIN);
        User user = Optional.ofNullable(getByLoginId(loginId)).orElseThrow(() ->
                new SimpleException(ErrorCode.USER_NOT_FOUND2));
        if (password.equals(user.getPassword())) {
            redisClusterUtils.set(ssoKey, System.currentTimeMillis(), TokenKey.USER_SSO_HASH.expire);
            return JwtUtil.createToken(loginId, 0);
        }
        throw new SimpleException(ErrorCode.PASSWORD_ERROR);
    }
}
